/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.wxtech.heartbeat.client;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Random;

import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger;

import com.wxtech.heartbeat.util.CHexConver;
import com.wxtech.heartbeat.util.Checksum;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * Handler implementation for the echo client.  It initiates the ping-pong
 * traffic between the echo client and server by sending the first message to
 * the server.
 */
public class DataCollectClientHandler extends ChannelInboundHandlerAdapter {
	private static final Logger logger = Logger.getLogger(DataCollectClientHandler.class);
	
//    private final ByteBuf firstMessage;
//    
//    private static final byte[] message = {
//    		0x68, 
//    		0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
//    		0x68,
//    		0x01,
//    		0x04, 0x00,
//    		0x17, 0x05, 0x22, 0x15, 0x34, 0x55,
//    		0x11,
//    		0x01, 0x00,
//    		0x02, 0x00,
//    		0x00, 
//    		0x45, 0x46, 0x47, 0x48,
//    		0x00,
//    		0x16
//    };

    /**
     * Creates a client-side handler.
     */
    public DataCollectClientHandler() {
    	/*
        firstMessage = Unpooled.buffer(EchoClient.SIZE);
        for (int i = 0; i < firstMessage.capacity(); i ++) {
            firstMessage.writeByte(0x68);
        }
        */
//    	firstMessage = Unpooled.buffer(32);
//    	firstMessage.setBytes(0, message);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {    	
    		//send hearbeat data to server
    		//一连上服务器就发送一个心跳信息，同时随意发一个信号
    		//最后就直接关闭连接
//        ctx.writeAndFlush(generateData());
//        ctx.writeAndFlush(generateBadDC());
    	ctx.writeAndFlush(generateDCFromString());
        logger.debug("channelActive()");
        ctx.close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ctx.write(msg);
        logger.debug("channelRead()");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
       ctx.flush();
       logger.debug("channelReadComplete()");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        logger.error(cause);
        ctx.close();
    }
    
    private ByteBuf generateData() {
    		byte[] rawData = new byte[75];
    		rawData[0] = 0x01;//cmdtype dc
    		//generateU16(rawData, 1);  //total
    		rawData[1] = 0x01;
    		generateU16(rawData, 2); //biaohao
    		
//    		rawData[2] = 0x00;
//    		rawData[3] = 0x01;//biaohao
    		
    		generateU64(rawData,4,8);
    		Calendar cal = Calendar.getInstance();
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
    		String year = sdf.format(cal.getTime());
    		rawData[12] = (byte) (Integer.valueOf(year) - 2000);//year
    		rawData[13] = (byte) (cal.get(Calendar.MONTH) + 1);//month start from 0
    		rawData[14] = (byte) cal.get(Calendar.DATE);//day
    		rawData[15] = (byte) cal.get(Calendar.HOUR);//hour
    		rawData[16] = (byte) cal.get(Calendar.MINUTE);//minute
    		rawData[17] = (byte) cal.get(Calendar.SECOND);//second
    		logger.debug(cal.getTime() + ",year=" + rawData[12]);
    		logger.debug("byte until 17 is good");
    		generateFloat(rawData, 18);
    		generateFloat(rawData, 22);
    		generateFloat(rawData, 26);
    		generateFloat(rawData, 30);
    		Random r = new Random();
    		for(int i = 34; i<= 45; i++) {
    			byte b = (byte)(r.nextInt(Byte.MAX_VALUE) & 0xFF);
    			logger.debug("rand byte=" + b);
    			rawData[i] = b;
    		}
    		generateFloat(rawData, 46);
    		generateFloat(rawData, 50);
    		generateFloat(rawData, 54);
    		generateFloat(rawData, 58);
    		generateFloat(rawData, 62);
    		generateFloat(rawData, 66);
    		generateFloat(rawData, 70);
    		byte b2 = (byte)(r.nextInt(Byte.MAX_VALUE) & 0xFF);
    		logger.debug("lastbyte = " + b2);
    		rawData[74] = b2;
    		
    		
    		ByteBuffer bb = ByteBuffer.wrap(rawData);
    		int crc16 = Checksum.crc16(Checksum.CRC16_AUG_CCITT, bb);
    		logger.info("rawData=" + Arrays.toString(rawData));
    		logger.info("crc16=" + crc16);
    		
    		ByteBuf data = Unpooled.buffer(77);
    		data.writeBytes(rawData);
    		data.writeShort(crc16);
    		logger.debug(Hex.encodeHexString(data.array()));
    		return data;
    }
    
    private ByteBuf generateBadDC() {
    		byte[] rawData = new byte[77];
    		generateBytes(rawData, 0, 77);
    		rawData[0] = 0x01;
    		rawData[1] = 0x01;
    		ByteBuf data = Unpooled.buffer(77);
    		data.writeBytes(rawData);
    		return data;
    }
    private void generateBytes(byte[] rawData, int startIndex, int length) {
    		//generate n byte data
    		String a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#=+)(*&";
    		Random r =  new Random();
    		for(int i=0; i<length;i++) {
    			int index = r.nextInt(a.length());
    			byte[] b = a.substring(index, index+1).getBytes();
    			rawData[startIndex + i] = b[b.length - 1];
    		}
    }

    private void generateU64(byte[] rawData, int startIndex, int length) {
		BigInteger bi = new BigInteger("170101000019");
		System.out.println(bi);
		Integer zero = new Integer(0);
		byte[] bytesBI = bi.toByteArray();
		byte[] bytes = {zero.byteValue(), zero.byteValue(), zero.byteValue(), bytesBI[0],bytesBI[1],bytesBI[2],bytesBI[3],bytesBI[4]};
		for(int i=0; i<length;i++) {
			rawData[startIndex + i] = bytes[i];
		}
    }
    
    private void generateU16(byte[] rawData, int startIndex) {
		Random r = new Random();
    	int num = r.nextInt(Short.MAX_VALUE) + 1;
//    	num = getMaxU16();
    	logger.debug("gU16=" + num);
    	rawData[startIndex + 1] = (byte) (num & 0xFF);
    	rawData[startIndex ] = (byte) (num >> 8 & 0xFF);
    }
    
    private int getMaxU16() {
    		int m = 65535;
    		return m;
    }
    
    private void generateFloat(byte[] rawData, int startIndex) {
    	Random r = new Random();
    	float f = -r.nextFloat() * 10;
    	logger.debug("generateFloat=" + f);
    	//byte [] dd = f2b(f);
    	
    	int bits = Float.floatToIntBits(f);
    	byte[]testbytes = new byte[4];
//    	rawData[startIndex] = (byte)(bits & 0xff);
//    	testbytes[0] = (byte)(bits & 0xff);
//    	rawData[startIndex + 1] = (byte)(bits>>8 & 0xff);
//    	testbytes[1] = (byte)(bits>>8 & 0xff);
//    	rawData[startIndex + 2] = (byte)(bits>>16 & 0xff);
//    	testbytes[2] = (byte)(bits>>16 & 0xff);
//    	rawData[startIndex + 3] = (byte)(bits>>24 & 0xff);
//    	testbytes[3] = (byte)(bits>>24 & 0xff);
    	
    	testbytes = ByteBuffer.allocate(4).putFloat(f).array();
    	rawData[startIndex] = testbytes[0];
    	rawData[startIndex + 1] = testbytes[1];
    	rawData[startIndex + 2] = testbytes[2];
    	rawData[startIndex + 3] = testbytes[3];

    	logger.debug("BYTE TO FLOAT=" + ByteBuffer.wrap(testbytes).getFloat());
    }
    
    private byte[] f2b(float f) {
    	//float buffer = 0f;  
        ByteBuffer bbuf = ByteBuffer.allocate(4);  
        bbuf.putFloat(f);  
        byte[] bBuffer = bbuf.array();  
        bBuffer=this.dataValueRollback(bBuffer);  
        return bBuffer;
    }
    

    
    
      
           //数值反传  
    private byte[] dataValueRollback(byte[] data) {  
        ArrayList<Byte> al = new ArrayList<Byte>();  
        for (int i = data.length - 1; i >= 0; i--) {  
            al.add(data[i]);  
        }  
      
        byte[] buffer = new byte[al.size()];  
        for (int i = 0; i <= buffer.length - 1; i++) {  
            buffer[i] = al.get(i);  
        }  
        return buffer;  
    }  
    
    /** 
     * 浮点转换为字节 
     *  
     * @param f 
     * @return 
     */  
    public static byte[] float2byte(float f) {  
          
        // 把float转换为byte[]  
        int fbit = Float.floatToIntBits(f);  
          
        byte[] b = new byte[4];    
        for (int i = 0; i < 4; i++) {    
            b[i] = (byte) (fbit >> (24 - i * 8));    
        }   
          
        // 翻转数组  
        int len = b.length;  
        // 建立一个与源数组元素类型相同的数组  
        byte[] dest = new byte[len];  
        // 为了防止修改源数组，将源数组拷贝一份副本  
        System.arraycopy(b, 0, dest, 0, len);  
        byte temp;  
        // 将顺位第i个与倒数第i个交换  
        for (int i = 0; i < len / 2; ++i) {  
            temp = dest[i];  
            dest[i] = dest[len - i - 1];  
            dest[len - i - 1] = temp;  
        }  
          
        return dest;  
          
    }  
    
    private ByteBuf generateDCFromString() {
    	String hex = "010001000400000402040701110615161933000000000000000086959E3FAF88A93F00000000000000000000000000000000000000000000000000000000000000000000000000000000014499";
		byte[] rawData = CHexConver.hexStr2Bytes(hex);
		logger.debug("generateDCFromString hex=" + hex);
		logger.debug("byte length=" + rawData.length);
		logger.debug("byte = " + Arrays.toString(rawData));
		ByteBuf data = Unpooled.buffer(rawData.length);
		data.writeBytes(rawData);
		return data;
}

    
}
